package ticketingsystem;

import java.util.Random;
import java.util.ArrayList;
import java.util.concurrent.ThreadLocalRandom;
public class Test {
	private static int maxthreadnum = 64;
	private static int[] threadnums = {4, 8, 16, 32, 64}; // concurrent thread number
	private static int routenum = 50;
	private static int coachnum = 20;
	private static int seatnum = 100;
	private static int stationnum = 30;

	private static int testnum = 1000000;
	private static int refund = 10;
	private static int buy = 40;
	private static int inqury = 60;

	private static TicketingDS tds;

	private static long[] tstart = new long[maxthreadnum];
	private static long[] tbuy = new long[maxthreadnum];
	private static long[] tref = new long[maxthreadnum];
	private static long[] tinq = new long[maxthreadnum];
	private static long[] buy_count = new long[maxthreadnum];
	private static long[] ref_count = new long[maxthreadnum];
	private static long[] inq_count = new long[maxthreadnum];

	private static int fi
	
	public static void main(String[] args) throws InterruptedException {
        for(int i :threadnums) {
			System.out.println("Test begin: \n");
			System.out.println("Thread num : "+i+"\n");
			tds = new TicketingDS(routenum, coachnum, seatnum, stationnum, i);
			fi = i;
			Thread[] test = new Thread[i];
			long startTime = System.currentTimeMillis();
			for (int j = 0; j < i; j++) {
				test[j] = new Thread(new worker());
				test[j].start();
			}
			for (int j = 0; j < i; j++) {
				test[j].join();
			}
			long totalTime = System.currentTimeMillis() - startTime;
			System.out.println("Avg Buy time: " + 1.0 * tbuy[i] / buy_count[i] +"ms\n");
			System.out.println("Avg Refund time: " + 1.0 * tref[i] / ref_count[i] +"ms\n");
			System.out.println("Avg Inqury time: " + 1.0 * tinq[i] / inq_count[i] +"ms\n");
			System.out.println("Throughput: " + 1000000.0 * i / totalTime +"op/ms\n");
		}


	    
	}
	public static String passengerName(int seed) {
		Random rand = new Random();
		long uid = rand.nextInt(seed);
		return "passenger" + uid;
	}
	private static class worker implements Runnable  {
		@Override
		public void run() {
			ThreadLocalRandom random = ThreadLocalRandom.current();
			Ticket ticket;
			ArrayList<Ticket> holdTicket = new ArrayList<>();

			for (int j = 0; j < testnum; j++) {
				int sel = random.nextInt(100);
				tstart[fi] = System.currentTimeMillis();
				if (sel < refund && holdTicket.size() > 0) {
					boolean refundResult = tds.refundTicket(holdTicket.remove(holdTicket.size() - 1));
					if(refundResult == false) {
						System.out.println("Error\n");
					}
					ref_count[fi]++;
					tref[fi] += System.currentTimeMillis() - tstart[fi];
				} else if (refund <= sel && sel < buy) {
					String passenger = passengerName(testnum);
					int route = random.nextInt(routenum) + 1;
					int departure = random.nextInt(stationnum - 1) + 1;
					int arrival = departure + random.nextInt(stationnum - departure) + 1;
					if ((ticket = tds.buyTicket(passenger, route, departure, arrival)) != null) {
						holdTicket.add(ticket);
					} else {
					}
					buy_count[fi]++;
					tbuy[fi] += System.currentTimeMillis() - tstart[fi];
				} else if (buy <= sel && sel < inqury) {
					int route = random.nextInt(routenum) + 1;
					int departure = random.nextInt(stationnum - 1) + 1;
					int arrival = departure + random.nextInt(stationnum - departure) + 1;
					int leftTicket = tds.inquiry(route, departure, arrival);
					inq_count[fi]++;
					tinq[fi] += System.currentTimeMillis() - tstart[fi];
				}
			}
		}
		}
}
